import logging
import os
import sys
import time
from datetime import datetime, timedelta
from logging.handlers import TimedRotatingFileHandler
from multiprocessing import Lock
from pathlib import Path

import colorlog
import pytz

from api.fm.configs import CONFIG, ConfigManager
from api.fm.libs import PrintUtils


class MultiProcessTimedRotatingFileHandler(TimedRotatingFileHandler):
    def __init__(self, filename, when, interval, backupCount=None, encoding=None, delay=False, utc=False):
        super().__init__(filename, when, interval, backupCount, encoding, delay, utc)
        self.rollover_lock = Lock()

    def doRollover(self):
        """
        执行日志文件切割，确保多进程环境下也能正确处理。
        使用进程锁来确保只有一个进程执行切割操作。
        """
        with self.rollover_lock:
            file_name = f"fm_{datetime.now().strftime('%Y-%m-%d')}.log"
            log_dir = CONFIG.get("LOG_DIR", "logs")  # 默认日志目录为 logs
            log_file = os.path.abspath(os.path.join(log_dir, file_name))
            os.makedirs(log_dir, exist_ok=True)
            self.baseFilename = log_file
            # 关闭当前的文件流
            if self.stream:
                self.stream.close()
                self.stream = None
            # 删除旧的日志文件（如果需要）
            if self.backupCount > 0:
                for s in self.getFilesToDelete():
                    os.remove(s)
            # 打开新的日志文件
            if not self.delay:
                self.stream = self._open()
            value = self.computeRollover(int(time.time()))
            # 更新下一个回滚时间
            super().__setattr__("rolloverAt", value)
            print(f"滚动进程日志: {self.baseFilename} ->  {datetime.fromtimestamp(value).strftime('%Y-%m-%d')}")

    def getFilesToDelete(self):
        """
        获取需要删除的旧的日志文件。
        计算最新时间与需要备份时间的差值
        遍历出所有日志文件判断时间是否超过差值，超过则删除 self.backupCount
        """
        dir_name = os.path.dirname(self.baseFilename)
        dir_files = os.listdir(dir_name)
        # 获取文件最新时间
        file_name = Path(self.baseFilename).name
        # 文件时间
        file_name_time = datetime.strptime(file_name[3:-4], "%Y-%m-%d")
        del_time = file_name_time - timedelta(days=self.backupCount)
        result = []
        for file_name in dir_files:
            file_name_time = datetime.strptime(file_name[3:-4], "%Y-%m-%d")
            if file_name_time < del_time:
                file_path = os.path.join(dir_name, file_name)
                result.append(file_path)
        return result


class LoggerManager:
    def __init__(self, config_manager: ConfigManager):
        self.config = config_manager.get_config()
        self.init_log()

    def create_log_directory(self, log_file):
        """
        创建日志文件目录（如果不存在）。
        """
        log_dir = os.path.dirname(log_file)
        os.makedirs(log_dir, exist_ok=True)

    def configure_log_handlers(self, log_file):
        """
        配置日志处理器（包括文件处理器和控制台处理器）。
        """
        backup_count = self.config.get("BACKUP_COUNT", 7)  # 默认保留7个备份文件

        log_handlers = [
            MultiProcessTimedRotatingFileHandler(  # 使用自定义的 MultiProcessTimedRotatingFileHandler
                filename=log_file,
                when="midnight",  # 以每天午夜切割日志
                interval=1,  # 每天切割
                backupCount=backup_count,
                encoding="utf-8",
            ),
            logging.StreamHandler(sys.stdout),  # 控制台输出处理器
        ]

        # 为控制台输出处理器设置颜色
        log_format = self.config.get("LOG_FORMAT", '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        console_handler = log_handlers[1]
        console_formatter = colorlog.ColoredFormatter(
            fmt=f'%(log_color)s{log_format}',  # 打印日志格式
            datefmt=self.config.get("LOG_DATEFORMAT", '%Y-%m-%d %H:%M:%S'),  # 默认日期格式
            log_colors={
                'DEBUG': 'light_cyan',
                'INFO': 'light_white',
                'WARNING': 'light_yellow',
                'ERROR': 'light_red',
                'CRITICAL': 'light_black,bg_green',
            }
        )
        console_handler.setFormatter(console_formatter)

        return log_handlers

    def configure_logging(self, log_handlers=None):
        """
        配置日志的基本设置，包括日志级别、格式以及处理器。
        """
        logging.basicConfig(
            level=self.config.get("LOG_LEVEL", "INFO"),  # 默认日志级别为 INFO
            format=self.config.get("LOG_FORMAT", '%(asctime)s - %(name)s - %(levelname)s - %(message)s'),
            datefmt=self.config.get("LOG_DATEFORMAT", '%Y-%m-%d %H:%M:%S'),
            handlers=log_handlers,  # 日志处理器
            force=True,  # 强制重新配置日志
        )

    def adjust_log_time(self):
        """
        根据配置调整日志时间，支持时区设置。
        """
        log_tz = self.config.get("LOG_TZ", 'Asia/Shanghai')  # 默认时区为上海
        if log_tz:
            pytz.timezone(log_tz)

    def init_log(self):
        """
        初始化日志，包括设置日志文件、目录、处理器等。
        """
        # 生成日志文件名，使用日期和时间（避免文件名冲突）
        file_name = f"fm_{datetime.now().strftime('%Y-%m-%d')}.log"
        log_dir = self.config.get("LOG_DIR", "logs")  # 默认日志目录为 logs
        log_file = os.path.abspath(os.path.join(log_dir, file_name))

        PrintUtils.print_colored(f"日志文件: {log_file}")

        if log_dir:
            # 创建日志目录（如果不存在）
            self.create_log_directory(log_file)

            # 配置日志处理器
            log_handlers = self.configure_log_handlers(log_file)
        else:
            raise ValueError("LOG_DIR not configured.")

        # 配置日志
        self.configure_logging(log_handlers)

        # 调整日志时间（如果需要）
        self.adjust_log_time()
